<?php

/**
 * 作者：云喵软件开发工作室
 * 官网：https://www.meoyun.com
 */

namespace app;

use Exception;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Validator as v;
use support\Redis;
use support\exception\BusinessException;
use support\Request;

class BaseController
{
    /** 默认分页大小 */
    protected const DEFAULT_PAGE_SIZE = 10;

    /** 最大分页大小 */
    protected const MAX_PAGE_SIZE = 1000;

    /**
     * 数据模型类
     */
    protected $dataModel = null;

    /**
     * 关联查询配置
     * 定义需要预加载的关联关系
     * @var array
     */
    protected array $with = [];

    /**
     * 允许搜索的字段列表
     * 只有在此数组中的字段才会被搜索条件处理
     * @var array
     */
    protected array $allowSearch = [];

    /**
     * 搜索字段配置
     * 定义每个搜索字段的搜索类型和处理方式
     * @var array
     */
    protected array $searchConfig = [];

    /**
     * 返回成功响应
     */
    public function success($data = null, $message = "SUCCESS", $code = 200): mixed
    {
        $result = ["code" => $code, "message" => $message];
        if ($data !== null) {
            $result["result"] = $data;
        }
        return json($result);
    }

    /**
     * 返回失败响应
     */
    public function fail($message = "FAIL", $code = 400): mixed
    {
        return json(["code" => $code, "message" => $message]);
    }

    /**
     * 获取当前登录用户ID
     * @param bool $isException 是否抛出异常，true抛出异常，false返回false
     * @return string|false 用户ID或false
     */
    protected function getUserId(bool $isException = true): false|string
    {
        $request = request();

        // 从请求头获取token
        $token = $request->header('Authorization');

        if (!$token) {
            if ($isException) {
                throw new BusinessException('缺少请求参数：Authorization', 2001);
            }
            return false;
        }

        // 从Redis获取用户ID
        $userId = Redis::get($token);

        if (!$userId) {
            if ($isException) {
                throw new BusinessException('token无效或已过期', 2001);
            }
            return false;
        }

        return (string)$userId;
    }

    /**
     * 构建基础查询对象
     *
     * 创建数据模型的查询构建器实例，并自动添加预设的关联查询
     * 子类可以重写此方法来自定义基础查询逻辑
     */
    protected function buildBaseQuery(): mixed
    {
        if (!$this->dataModel) {
            throw new BusinessException('数据模型未设置，请在控制器中设置 $dataModel 属性');
        }

        if (!class_exists($this->dataModel)) {
            throw new BusinessException("数据模型类 {$this->dataModel} 不存在");
        }

        try {
            $query = $this->dataModel::query();

            // 添加关联查询
            if (!empty($this->with)) {
                $query->with($this->with);
            }

            return $query;
        } catch (Exception $e) {
            throw new BusinessException("创建查询构建器失败: {$e->getMessage()}", 0, $e);
        }
    }

    /**
     * 获取分页数据列表
     *
     * 处理分页查询请求，支持搜索条件过滤、排序和分页
     * 返回标准化的分页响应格式，包含数据列表和分页信息
     */
    public function getListByPage(Request $request): mixed
    {
        $pageSize = max(1, min(self::MAX_PAGE_SIZE, (int)$request->input('pageSize', self::DEFAULT_PAGE_SIZE)));
        $queryForm = $request->input('queryForm', []);

        $query = $this->buildBaseQuery();
        $this->handleSearchConditions($query, $queryForm);

        $paginate = $query->orderBy('created_at', 'desc')->paginate($pageSize);

        return $this->dataByPage($paginate);
    }

    /**
     * 处理搜索条件
     */
    protected function handleSearchConditions(mixed $query, array $queryForm): void
    {
        $searchWhere = array_intersect(array_keys($queryForm), $this->allowSearch);

        foreach ($searchWhere as $field) {

            $value = $queryForm[$field];

            // 跳过空值
            if (!$value) continue;

            // 检查字段是否有搜索配置，如果没有则使用默认的精确匹配
            if (!isset($this->searchConfig[$field])) {
                $query->where($field, '=', $value);
                continue;
            }

            // 获取字段的搜索配置
            $config = $this->searchConfig[$field];
            $searchType = $config['type'];

            $this->applySearchCondition($query, $field, $value, $searchType);
        }
    }

    /**
     * 应用搜索条件
     */
    protected function applySearchCondition($query, string $field, $value, string $searchType): void
    {
        switch ($searchType) {
            case 'like':
                $query->where($field, 'like', '%' . $value . '%');
                break;
            case 'gt':
            case 'gte':
            case 'lt':
            case 'lte':
                //比较搜索（大于、小于等）
                $operatorMap = ['gt' => '>', 'gte' => '>=', 'lt' => '<', 'lte' => '<='];
                $query->where($field, $operatorMap[$searchType], $value);
                break;
            case 'between':
                if (is_array($value) && count($value) === 2) {
                    $query->whereBetween($field, [$value[0], $value[1]]);
                }
                break;
            case 'in':
                $query->whereIn($field, $this->processArrayValue($value));
                break;
            case 'date_range':
                $this->applyDateRangeSearch($query, $field, $value);
                break;
            default:
                $query->where($field, '=', $value);
                break;
        }
    }

    /**
     * 处理数组值
     */
    private function processArrayValue($value): array
    {
        return is_array($value) ? $value : array_map('trim', explode(',', $value));
    }


    /**
     * 日期范围搜索
     */
    protected function applyDateRangeSearch($query, string $field, $value): void
    {
        if (!is_array($value) || count($value) !== 2) return;

        [$startDate, $endDate] = $value;

        if ($startDate && $endDate) {
            $query->whereBetween($field, [$startDate . ' 00:00:00', $endDate . ' 23:59:59']);
        } elseif ($startDate) {
            $query->where($field, '>=', $startDate . ' 00:00:00');
        } elseif ($endDate) {
            $query->where($field, '<=', $endDate . ' 23:59:59');
        }
    }

    /**
     * 获取数据列表
     */
    public function getList()
    {
        try {
            $query = $this->buildBaseQuery();
            $list = $query->orderBy('created_at', 'desc')->get();
            return $this->success($list);
        } catch (Exception $e) {
            throw new BusinessException("获取数据列表失败: {$e->getMessage()}", 0, $e);
        }
    }

    /**
     * 获取数据详情
     */
    public function getInfo(Request $request)
    {
        try {
            $params = v::input($request->all(), [
                'id' => v::stringType()->notEmpty()->setName("ID")
            ]);
        } catch (ValidationException $e) {
            return $this->fail($e->getMessage());
        }

        try {
            $query = $this->buildBaseQuery();
            $list = $query->where('id', $params["id"])->firstOrFail();
            return $this->success($list);
        } catch (Exception $e) {
            throw new BusinessException("获取数据列表失败: {$e->getMessage()}", 400, $e);
        }
    }

    /**
     * 返回分页数据响应
     */
    protected function dataByPage($paginate): mixed
    {
        return $this->success([
            'list' => $paginate->items(),
            'total' => $paginate->total(),
            'page' => $paginate->currentPage(),
            'pageSize' => $paginate->perPage(),
            'lastPage' => $paginate->lastPage(),
            'hasMore' => $paginate->hasMorePages()
        ]);
    }
}
